import time
from datetime import datetime
from threading import Lock


class Participant:
    def __init__(self, participant_id, coordinator):
        self.participant_id = participant_id  # 参与者id,主线程创建该参与者时提供
        self.request_list = coordinator.request_list  # 绑定协调者的请求列表
        self.request_time = datetime.now()  # 请求时间
        self.get_response = True  # 是否得到响应
        self.is_using = False  # 是否正在使用
        self.lock = coordinator.lock  # 绑定同一个资源互斥锁

    # TODO:参与者只负责向协调者的处理请求的队列放请求，然后等待响应
    def start(self):
        while 1:
            if self.get_response:  # 如果请求已被处理，则可以发起下一次请求
                self.get_response = False
                self.request_time = datetime.now()
                self.send_request()
                self.working()  # 进入工作阻塞状态，直到收到响应
            time.sleep(2)

    def send_request(self):
        self.request_list.append(f'{self.request_time}_{self.participant_id}')
        self.request_list.sort()
        print(f'参与者{self.participant_id}:已于{self.request_time} 发送请求，正在等待响应！')

    def working(self):
        while 1:
            if self.get_response:  # 得到允许表示有资格
                with self.lock:  # 但是还得拿到互斥锁才能访问
                    self.is_using = True
                    print(f'参与者{self.participant_id}:请求已被协调者允许，开始访问临界资源！')
                    # TODO：此处可以为访问临界资源的相关操作,此处用睡眠1秒代替
                    time.sleep(1)
                    print(f'参与者{self.participant_id}:访问临界资源完成，可以继续工作了！')
                    self.is_using = False
                    return


class Coordinator:
    def __init__(self):
        self.thread_list = []  # 工作线程列表，初始最后一个为协调者
        self.participant_list = []
        self.request_list = []
        self.response_obj = ""
        self.response_time = datetime.now()
        self.lock = Lock()  # 临界资源访问的锁

    # TODO：协调者只负责处理最早的请求，然后回复，可扩展为处理的同时修改请求对象的是否收到响应的属性
    #   这样就不需要在主线程再设置一个单独的检查者线程了
    def start(self):
        while 1:
            # print(self.request_list)
            self.send_response()
            time.sleep(1)

    def send_response(self):
        if len(self.request_list) > 0:
            self.response_obj = self.request_list[0]
            # TODO: 处理当前列表中最早的请求
            self.working()
            # 删除该请求，此处使用del的目的是在删除元素的同时释放其空间，节约内存，
            # 如果仅想达到删除列表内元素的目的，也可以使用列表自带的remove方法
            del self.request_list[0]

    def working(self):
        # TODO:已扩展为处理的同时修改请求对象的是否收到响应的属性
        #   这样就不需要在主线程再设置一个单独的检查者线程了，而且可以直接处理，不需要一直循环检查
        response = self.response_obj.split('_')[1]  # 当前处理的参与者id
        response = int(response)
        self.participant_list[response].get_response = True  # 设置该参与者是否得到响应的标志为True
        self.response_time = datetime.now()  # 响应时间
        print(f'协调者：来自参与者{response}的请求处理完成！处理时间：{self.response_time}')
        while self.participant_list[response].is_using:
            time.sleep(0.2)  # 每0.2秒检查该参与者是否还在使用该临界资源
            continue
